package com.hotel.management.service.impl;

import com.hotel.management.dto.EmployeeDTO;
import com.hotel.management.dto.EmployeeQueryDTO;
import com.hotel.management.dto.PageResult;
import com.hotel.management.entity.Employee;
import com.hotel.management.exception.DuplicateEmployeeException;
import com.hotel.management.exception.EmployeeNotFoundException;
import com.hotel.management.mapper.EmployeeMapper;
import com.hotel.management.service.EmployeeService;
import com.hotel.management.util.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;

import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 员工服务实现类
 * 实现员工管理相关的业务逻辑
 * 
 * @author Hotel Management Team
 * @version 1.0.0
 * @since 2024-06-28
 */
@Service
@Transactional(rollbackFor = Exception.class)
@Validated
public class EmployeeServiceImpl implements EmployeeService {

    private static final Logger log = LoggerFactory.getLogger(EmployeeServiceImpl.class);

    private final EmployeeMapper employeeMapper;

    public EmployeeServiceImpl(EmployeeMapper employeeMapper) {
        this.employeeMapper = employeeMapper;
    }

    @Override
    public EmployeeDTO createEmployee(@Valid @NotNull EmployeeDTO employeeDTO) {
        log.info("开始创建员工: {}", employeeDTO.getName());
        
        // 检查手机号是否已存在
        if (StringUtils.hasText(employeeDTO.getPhone())) {
            Employee existingByPhone = employeeMapper.selectByPhone(employeeDTO.getPhone());
            if (existingByPhone != null) {
                throw new DuplicateEmployeeException("手机号", employeeDTO.getPhone());
            }
        }
        
        // 检查邮箱是否已存在
        if (StringUtils.hasText(employeeDTO.getEmail())) {
            Employee existingByEmail = employeeMapper.selectByEmail(employeeDTO.getEmail());
            if (existingByEmail != null) {
                throw new DuplicateEmployeeException("邮箱", employeeDTO.getEmail());
            }
        }
        
        // 转换为实体对象
        Employee employee = convertToEntity(employeeDTO);
        employee.setCreatedTime(new Date());
        employee.setUpdatedTime(new Date());
        
        // 保存到数据库
        int result = employeeMapper.insert(employee);
        if (result <= 0) {
            throw new RuntimeException("创建员工失败");
        }
        
        log.info("员工创建成功: ID={}, 姓名={}", employee.getId(), employee.getName());
        return convertToDTO(employee);
    }

    @Override
    @Transactional(readOnly = true)
    public EmployeeDTO getEmployeeById(@NotNull Long id) {
        log.debug("查询员工信息: ID={}", id);
        
        Employee employee = employeeMapper.selectById(id);
        if (employee == null) {
            throw new EmployeeNotFoundException(id);
        }
        
        return convertToDTO(employee);
    }

    @Override
    @Transactional(readOnly = true)
    public List<EmployeeDTO> getAllEmployees() {
        log.debug("查询所有员工信息");
        
        List<Employee> employees = employeeMapper.selectAll();
        return employees.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    public EmployeeDTO updateEmployee(@NotNull Long id, @Valid @NotNull EmployeeDTO employeeDTO) {
        log.info("开始更新员工信息: ID={}", id);
        
        // 检查员工是否存在
        Employee existingEmployee = employeeMapper.selectById(id);
        if (existingEmployee == null) {
            throw new EmployeeNotFoundException(id);
        }
        
        // 检查手机号是否被其他员工使用
        if (StringUtils.hasText(employeeDTO.getPhone()) && 
            !employeeDTO.getPhone().equals(existingEmployee.getPhone())) {
            Employee existingByPhone = employeeMapper.selectByPhone(employeeDTO.getPhone());
            if (existingByPhone != null && !existingByPhone.getId().equals(id)) {
                throw new DuplicateEmployeeException("手机号", employeeDTO.getPhone());
            }
        }
        
        // 检查邮箱是否被其他员工使用
        if (StringUtils.hasText(employeeDTO.getEmail()) && 
            !employeeDTO.getEmail().equals(existingEmployee.getEmail())) {
            Employee existingByEmail = employeeMapper.selectByEmail(employeeDTO.getEmail());
            if (existingByEmail != null && !existingByEmail.getId().equals(id)) {
                throw new DuplicateEmployeeException("邮箱", employeeDTO.getEmail());
            }
        }
        
        // 更新员工信息
        Employee updateEmployee = convertToEntity(employeeDTO);
        updateEmployee.setId(id);
        updateEmployee.setCreatedTime(existingEmployee.getCreatedTime());
        updateEmployee.setUpdatedTime(new Date());
        
        // 只更新非空字段
        BeanUtils.copyPropertiesIgnoreNull(updateEmployee, existingEmployee);
        existingEmployee.setUpdatedTime(new Date());
        
        int result = employeeMapper.updateById(existingEmployee);
        if (result <= 0) {
            throw new RuntimeException("更新员工信息失败");
        }
        
        log.info("员工信息更新成功: ID={}, 姓名={}", id, existingEmployee.getName());
        return convertToDTO(existingEmployee);
    }

    @Override
    public void deleteEmployee(@NotNull Long id) {
        log.info("开始删除员工: ID={}", id);
        
        // 检查员工是否存在
        Employee employee = employeeMapper.selectById(id);
        if (employee == null) {
            throw new EmployeeNotFoundException(id);
        }
        
        int result = employeeMapper.deleteById(id);
        if (result <= 0) {
            throw new RuntimeException("删除员工失败");
        }
        
        log.info("员工删除成功: ID={}, 姓名={}", id, employee.getName());
    }

    @Override
    @Transactional(readOnly = true)
    public List<EmployeeDTO> getEmployeesByName(@NotNull String name) {
        log.debug("根据姓名查询员工: {}", name);
        
        List<Employee> employees = employeeMapper.selectByName(name);
        return employees.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(readOnly = true)
    public List<EmployeeDTO> getEmployeesByPosition(@NotNull String position) {
        log.debug("根据职位查询员工: {}", position);
        
        List<Employee> employees = employeeMapper.selectByPosition(position);
        return employees.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(readOnly = true)
    public List<EmployeeDTO> getEmployeesByStatus(@NotNull String status) {
        log.debug("根据状态查询员工: {}", status);
        
        List<Employee> employees = employeeMapper.selectByStatus(status);
        return employees.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(readOnly = true)
    public List<EmployeeDTO> getEmployeesByRoleId(@NotNull Long roleId) {
        log.debug("根据角色ID查询员工: {}", roleId);
        
        List<Employee> employees = employeeMapper.selectByRoleId(roleId);
        return employees.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(readOnly = true)
    public PageResult<EmployeeDTO> getEmployeesWithPage(@Valid @NotNull EmployeeQueryDTO queryDTO) {
        log.debug("分页查询员工信息: {}", queryDTO);
        
        // 查询总数
        int total = employeeMapper.countByCondition(
                queryDTO.getName(), 
                queryDTO.getPosition(), 
                queryDTO.getStatus()
        );
        
        if (total == 0) {
            return PageResult.empty(queryDTO.getPageNum(), queryDTO.getPageSize());
        }
        
        // 查询数据
        List<Employee> employees = employeeMapper.selectByConditionWithPage(
                queryDTO.getName(),
                queryDTO.getPosition(),
                queryDTO.getStatus(),
                queryDTO.getOffset(),
                queryDTO.getLimit()
        );
        
        List<EmployeeDTO> employeeDTOs = employees.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
        
        return PageResult.of(employeeDTOs, total, queryDTO.getPageNum(), queryDTO.getPageSize());
    }

    @Override
    public int batchCreateEmployees(@NotEmpty List<@Valid EmployeeDTO> employeeDTOs) {
        log.info("开始批量创建员工: 数量={}", employeeDTOs.size());
        
        // 检查重复数据
        for (EmployeeDTO dto : employeeDTOs) {
            if (StringUtils.hasText(dto.getPhone())) {
                Employee existingByPhone = employeeMapper.selectByPhone(dto.getPhone());
                if (existingByPhone != null) {
                    throw new DuplicateEmployeeException("手机号", dto.getPhone());
                }
            }
            
            if (StringUtils.hasText(dto.getEmail())) {
                Employee existingByEmail = employeeMapper.selectByEmail(dto.getEmail());
                if (existingByEmail != null) {
                    throw new DuplicateEmployeeException("邮箱", dto.getEmail());
                }
            }
        }
        
        // 转换为实体对象
        List<Employee> employees = employeeDTOs.stream()
                .map(dto -> {
                    Employee employee = convertToEntity(dto);
                    employee.setCreatedTime(new Date());
                    employee.setUpdatedTime(new Date());
                    return employee;
                })
                .collect(Collectors.toList());
        
        int result = employeeMapper.batchInsert(employees);
        log.info("批量创建员工完成: 成功数量={}", result);
        
        return result;
    }

    @Override
    public int batchDeleteEmployees(@NotEmpty List<Long> ids) {
        log.info("开始批量删除员工: IDs={}", ids);
        
        int result = employeeMapper.batchDeleteByIds(ids);
        log.info("批量删除员工完成: 成功数量={}", result);
        
        return result;
    }

    @Override
    public void updateEmployeeStatus(@NotNull Long id, @NotNull String status) {
        log.info("更新员工状态: ID={}, 状态={}", id, status);
        
        // 检查员工是否存在
        Employee employee = employeeMapper.selectById(id);
        if (employee == null) {
            throw new EmployeeNotFoundException(id);
        }
        
        int result = employeeMapper.updateStatus(id, status);
        if (result <= 0) {
            throw new RuntimeException("更新员工状态失败");
        }
        
        log.info("员工状态更新成功: ID={}, 新状态={}", id, status);
    }

    @Override
    @Transactional(readOnly = true)
    public boolean existsById(@NotNull Long id) {
        Employee employee = employeeMapper.selectById(id);
        return employee != null;
    }

    @Override
    @Transactional(readOnly = true)
    public EmployeeDTO getEmployeeByPhone(@NotNull String phone) {
        log.debug("根据手机号查询员工: {}", phone);
        
        Employee employee = employeeMapper.selectByPhone(phone);
        return employee != null ? convertToDTO(employee) : null;
    }

    @Override
    @Transactional(readOnly = true)
    public EmployeeDTO getEmployeeByEmail(@NotNull String email) {
        log.debug("根据邮箱查询员工: {}", email);
        
        Employee employee = employeeMapper.selectByEmail(email);
        return employee != null ? convertToDTO(employee) : null;
    }

    @Override
    @Transactional(readOnly = true)
    public long countAllEmployees() {
        return employeeMapper.countAll();
    }

    @Override
    @Transactional(readOnly = true)
    public long countEmployeesByCondition(@Valid @NotNull EmployeeQueryDTO queryDTO) {
        return employeeMapper.countByCondition(
                queryDTO.getName(),
                queryDTO.getPosition(),
                queryDTO.getStatus()
        );
    }

    @Override
    public EmployeeDTO convertToDTO(Employee employee) {
        if (employee == null) {
            return null;
        }
        
        EmployeeDTO dto = new EmployeeDTO();
        BeanUtils.copyProperties(employee, dto);
        return dto;
    }

    @Override
    public Employee convertToEntity(EmployeeDTO employeeDTO) {
        if (employeeDTO == null) {
            return null;
        }
        
        Employee employee = new Employee();
        BeanUtils.copyProperties(employeeDTO, employee);
        return employee;
    }
}
